package pers.dawnyang.modular.system.excelListener;

import java.util.ArrayList;
import java.util.List;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.Getter;
import pers.dawnyang.common.domain.ExcelMsg;
import pers.dawnyang.common.domain.entity.SysUser;
import pers.dawnyang.config.cache.ConfigUtils;
import pers.dawnyang.config.cache.DictTransUtil;
import pers.dawnyang.modular.system.domain.request.user.UserExcelReq;
import pers.dawnyang.modular.system.service.UserService;

/**
 * EasyExcel 数据导入处理类
 * 
 * @author dawn yang
 * 
 */

public class UserExcelResListener extends AnalysisEventListener<UserExcelReq> {
  private static final Logger LOGGER = LoggerFactory.getLogger(UserExcelResListener.class);
  /**
   * 每隔5条存储数据库，实际使用中可以3000条，然后清理list ，方便内存回收
   */
  private static final int BATCH_COUNT = 5;
  List<SysUser> list = new ArrayList<>();

  @Getter
  ExcelMsg excelMsg = new ExcelMsg();

  private UserService userService;

  /**
   * 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
   *
   * @param uploadDAO
   */
  public UserExcelResListener(UserService userService) {
    this.userService = userService;
  }

  /**
   * 这个每一条数据解析都会来调用
   *
   * @param data one row value. Is is same as {@link AnalysisContext#readRowHolder()}
   * @param context
   */
  @Override
  public void invoke(UserExcelReq data, AnalysisContext context) {
    // LOGGER.info("解析到一条数据:{}", JSON.toJSONString(data));
    String defaultPwd = ConfigUtils.getValue("defaultPwd");
    String defualtPwd = new Md5Hash(defaultPwd, data.getUserCode()).toString();
    DictTransUtil.nameToCode(data);
    SysUser sysUser = new SysUser();
    BeanUtils.copyProperties(data, sysUser);
    sysUser.setSex(Integer.valueOf(data.getSex()));
    sysUser.setUserStatus(Integer.valueOf(data.getUserStatus()));
    sysUser.setPassword(defualtPwd);
    sysUser.setSalt(data.getUserCode());
    list.add(sysUser);
    // 达到BATCH_COUNT了，需要去存储一次数据库，防止数据几万条数据在内存，容易OOM
    if (list.size() >= BATCH_COUNT) {
      saveData();
      // 存储完成清理 list
      list.clear();
    }
  }

  /**
   * 所有数据解析完成了 都会来调用
   *
   * @param context
   */
  @Override
  public void doAfterAllAnalysed(AnalysisContext context) {
    // 这里也要保存数据，确保最后遗留的数据也存储到数据库
    saveData();
    LOGGER.info("所有数据解析完成！");
  }

  /**
   * 加上存储数据库
   */
  private void saveData() {
    LOGGER.info("{}条数据，开始存储数据库！", list.size());
    for (SysUser sysUser : list) {
      LambdaQueryWrapper<SysUser> lqw = new LambdaQueryWrapper<>();
      lqw.eq(SysUser::getUserCode, sysUser.getUserCode());
      SysUser one = userService.getOne(lqw);
      if (null != one) {
        excelMsg.falseInc();
        excelMsg.addMsg("用户编码" + sysUser.getUserCode() + "已存在");
        LOGGER.info("用户编码{}已存在", sysUser.getUserCode());
      } else {
        excelMsg.successInc();
        userService.save(sysUser);
      }
    }
    // userService.saveBatch(list);
    LOGGER.info("存储数据库成功！");
  }

  @Override
  public void onException(Exception exception, AnalysisContext context) {
    LOGGER.error("解析失败，但是继续解析下一行:{}", exception.getMessage());
    // 如果是某一个单元格的转换异常 能获取到具体行号
    // 如果要获取头的信息 配合invokeHeadMap使用
    excelMsg.falseInc();
    int falseNum = context.getCurrentRowNum() + 1;
    excelMsg.addMsg("第" + falseNum + "行数据错误！");

    /*
     * if (exception instanceof ExcelDataConvertException) { ExcelDataConvertException
     * excelDataConvertException = (ExcelDataConvertException)exception;
     * LOGGER.error("第{}行，第{}列解析异常", excelDataConvertException.getRowIndex(),
     * excelDataConvertException.getColumnIndex()); excelMsg.falseInc(); excelMsg.addMsg("第" +
     * excelDataConvertException.getRowIndex() + "行，第" + excelDataConvertException.getColumnIndex()
     * + "列解析异常"); }
     */
  }
}
